/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*        http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
主要功能：
1. 自定义 EditText 组件，用于便签编辑界面，支持监听删除、回车和文本变化事件；
2. 实现光标精确控制（根据触摸位置定位光标）；
3. 提供 URL 链接的上下文菜单处理逻辑（如电话、网页、邮件等）；
4. 封装索引设置、焦点变化响应、文本监听接口等功能，便于在列表中动态增删编辑框。
*/

package net.micode.notes.ui;

import android.content.Context;
import android.graphics.Rect;
import android.text.Layout;
import android.text.Selection;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.MotionEvent;
import android.widget.EditText;
 
import net.micode.notes.R;
 
import java.util.HashMap;
import java.util.Map;
 

//自定义EditText，用于便签编辑界面，支持删除、回车、文本变化监听等功能。
public class NoteEditText extends EditText {
    private static final String TAG = "NoteEditText"; //日志标签
    private int mIndex; //当前EditText的索引,用于标识在列表中的位置
    private int mSelectionStartBeforeDelete; //删除操作前的光标起始位置,用于判断删除条件
 
    //定义URL协议常量,用于识别链接类型
    private static final String SCHEME_TEL = "tel:";
    private static final String SCHEME_HTTP = "http:";
    private static final String SCHEME_EMAIL = "mailto:";
 
    //定义URL协议与对应资源ID的映射,用于上下文菜单显示不同操作
    private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();
    static {
        sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel); //电话协议,对应拨打电话
        sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web); //HTTP协议,对应打开网页
        sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email);//邮件协议，对应发送邮件
    }
 
    //文本变化监听接口，由NoteEditActivity实现
    public interface OnTextViewChangeListener {
        
        //当按下删除键且文本为空时，删除当前EditText
        //index:当前EditText的索引,text:当前文本内容（可能为空）
        void onEditTextDelete(int index, String text);
 
        //按下回车键时，在当前EditText后添加新的EditText
        //index:当前EditText的索引,text:新EditText的初始文本
        void onEditTextEnter(int index, String text);
 
        //文本变化时，隐藏或显示选项菜单
        //index:当前EditText的索引,hasText:当前是否有文本内容
        void onTextChange(int index, boolean hasText);
    }
 
    private OnTextViewChangeListener mOnTextViewChangeListener; //文本变化监听器
 
    //构造函数
    public NoteEditText(Context context) {
        super(context, null);
        mIndex = 0; //初始化索引
    }
 
    //设置当前EditText的索引
    public void setIndex(int index) {
        mIndex = index;
    }
 
    //设置文本变化监听器
    public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
        mOnTextViewChangeListener = listener;
    }
 
    //构造函数
    public NoteEditText(Context context, AttributeSet attrs) {
        super(context, attrs, android.R.attr.editTextStyle);
    }
 
    //构造函数
    public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //获取触摸点的坐标
                int x = (int) event.getX();
                int y = (int) event.getY();
                x -= getTotalPaddingLeft();
                y -= getTotalPaddingTop();
                x += getScrollX();
                y += getScrollY();
 
                //根据坐标设置光标位置
                Layout layout = getLayout();
                int line = layout.getLineForVertical(y);//垂直方向对应的行
                int off = layout.getOffsetForHorizontal(line, x);//水平方向偏移量
                Selection.setSelection(getText(), off);//设置光标位置
                break;
            default:
                // 在这里处理其他触摸事件，或者什么都不做
                // 如果不需要处理其他事件，可以保留 break 语句，或者添加日志记录等
                break;
        }
 
        return super.onTouchEvent(event);
    }
 
    //按下按键事件处理
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_ENTER:
                if (mOnTextViewChangeListener != null) {
                    return false; //拦截回车键事件
                }
                break;
            case KeyEvent.KEYCODE_DEL:
                mSelectionStartBeforeDelete = getSelectionStart(); //记录删除前的光标位置
                break;
            default:
                break;
        }
        return super.onKeyDown(keyCode, event);
    }
 
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_DEL:
                if (mOnTextViewChangeListener != null) {
                    //如果光标在起始位置且不是第一个EditText，则删除当前EditText
                    if (0 == mSelectionStartBeforeDelete && mIndex != 0) {
                        mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
                        return true;
                    }
                } else {
                    Log.d(TAG, "OnTextViewChangeListener was not seted");
                }
                break;
            case KeyEvent.KEYCODE_ENTER:
                if (mOnTextViewChangeListener != null) {
                    //在光标位置拆分文本，并在当前EditText后添加新的EditText
                    int selectionStart = getSelectionStart();
                    String text = getText().subSequence(selectionStart, length()).toString();
                    setText(getText().subSequence(0, selectionStart));
                    mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text);
                } else {
                    Log.d(TAG, "OnTextViewChangeListener was not seted");
                }
                break;
            default:
                break;
        }
        return super.onKeyUp(keyCode, event);
    }
    
    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        if (mOnTextViewChangeListener != null) {
            //根据焦点状态和文本内容，通知监听器文本变化
            if (!focused && TextUtils.isEmpty(getText())) {
                mOnTextViewChangeListener.onTextChange(mIndex, false);
            } else {
                mOnTextViewChangeListener.onTextChange(mIndex, true);
            }
        }
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
    }
 
    //创建上下文菜单（长按URL时触发）
    @Override
    protected void onCreateContextMenu(ContextMenu menu) {
        if (getText() instanceof Spanned) {
            //获取选中文本的起始和结束位置
            int selStart = getSelectionStart();
            int selEnd = getSelectionEnd();
 
            int min = Math.min(selStart, selEnd);
            int max = Math.max(selStart, selEnd);

            //获取选中文本中的URLSpan
            final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
            if (urls.length == 1) {
                //根据URL协议设置菜单项
                int defaultResId = 0;
                for (String schema : sSchemaActionResMap.keySet()) {
                    if (urls[0].getURL().indexOf(schema) >= 0) {
                        defaultResId = sSchemaActionResMap.get(schema);
                for (Map.Entry<String, Integer> entry : sSchemaActionResMap.entrySet()) {
                    String schema = entry.getKey();
                    Integer resId = entry.getValue();
                    if (urls[0].getURL().indexOf(schema) >= 0) {
                        defaultResId = resId;
                        break;
                    }
                }

                if (defaultResId == 0) {
                    defaultResId = R.string.note_link_other; //默认菜单项
                }

                //添加菜单项并设置点击事件
                menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
                        new OnMenuItemClickListener() {
                            public boolean onMenuItemClick(MenuItem item) {
                                // 跳转到URL对应的页面
                                urls[0].onClick(NoteEditText.this);
                                return true;
                            }
                        });
            }
        }
        super.onCreateContextMenu(menu);
    }
}